// NPack.Blas.OperationsEngine.h

#include "cblas.h"
#pragma once

using namespace System;
using namespace System::Collections::Generic;
using namespace NPack::Interfaces;

namespace NPack { namespace Blas { namespace OperationsEngine {

	generic <typename T>
	where T:  value struct, ValueType, IEquatable<T>, IComparable<T>, IComputable<T>, IConvertible, IFormattable
	public ref class BlasMatrixOperations : NPack::Interfaces::IMatrixOperations<T>
	{
	public:
		virtual IMatrix<T>^ Add(IMatrix<T>^ lhs, IMatrix<T>^ rhs) 
		{
			throw gcnew NotImplementedException();
		}
		
		virtual IMatrix<T>^ Subtract(IMatrix<T>^ lhs, IMatrix<T>^ rhs)
		{
			throw gcnew NotImplementedException();
		}
		
        virtual IMatrix<T>^ Multiply(IMatrix<T>^ lhs, IMatrix<T>^ rhs)
		{
			if(lhs->ColumnCount != rhs->RowCount)
			{
				throw gcnew ArgumentException(
					"The number of columns of the left-hand matrix must equal the number of rows of the right-hand matrix.");
			}

			Matrix<T>^ m = gcnew Matrix<T>(lhs->Format, lhs->RowCount, rhs->ColumnCount);
			/*
			Int32 order = (m->Format == MatrixFormat::ColumnMajor ? CBLAS_ORDER::CblasColMajor : CBLAS_ORDER::CblasRowMajor);
			Int32 transpose = (rhs->Format != m->Format ? CBLAS_TRANSPOSE::CblasTrans : CBLAS_TRANSPOSE::CblasNoTrans);
			
			pin_ptr<T> lhsElements = &(lhs->Elements[0][0]);
			pin_ptr<T> rhsElements = &(rhs->Elements[0][0]);
			pin_ptr<T> destElements = &(m->Elements[0][0]);

			if(T::typeid == DoubleComponent::typeid)
			{
				Double* a = (Double*)lhsElements;
				Double* b = (Double*)rhsElements;
				Double* c = (Double*)destElements;

				//::cblas_dgemm(order, CBLAS_TRANSPOSE::CblasNoTrans, transpose, lhs->RowCount, rhs->ColumnCount, lhs->ColumnCount, 0, 
				//	(Double*)lhsElements, 0, (Double*)rhsElements, 0, 0, (Double*)destElements, 0);
				::cblas_dgemm((CBLAS_ORDER)order, CBLAS_TRANSPOSE::CblasNoTrans, (CBLAS_TRANSPOSE)transpose, 
					lhs->RowCount, rhs->ColumnCount, lhs->ColumnCount, 0, a, 0, b, 0, 0, c, 0);
			}
			else if(T::typeid == SingleComponent::typeid)
			{
				::cblas_sgemm((CBLAS_ORDER)order, CBLAS_TRANSPOSE::CblasNoTrans, (CBLAS_TRANSPOSE)transpose, lhs->RowCount, rhs->ColumnCount, lhs->ColumnCount, 0, 
					(float*)lhsElements, 0, (float*)rhsElements, 0, 0, (float*)destElements, 0);
			}
*/
			return m;
		}
		
        virtual void Multiply(IMatrix<T>^ lhs, IMatrix<T>^ %rhs)
		{
		}
		
        virtual void Multiply(IMatrix<T>^ %lhs, IMatrix<T>^ rhs)
		{
		}

		virtual IVector<T>^ Multiply(IMatrix<T>^ multiplier, IVector<T>^ vector)
		{
			throw gcnew NotImplementedException();
		}
		
		virtual IVector<T>^ Multiply(IVector<T>^ vector, IMatrix<T>^ multiplier)
		{
			throw gcnew NotImplementedException();
		}

		virtual IEnumerable<IMatrix<T>^>^ Multiply(IMatrix<T>^ lhs, IEnumerable<IMatrix<T>^>^ rhs) 
		{
			throw gcnew NotImplementedException();
		}
		
		virtual IEnumerable<IMatrix<T>^>^ Multiply(IEnumerable<IMatrix<T>^>^ lhs, IMatrix<T>^ rhs) 
		{
			throw gcnew NotImplementedException();
		}
		
		virtual IEnumerable<IVector<T>^>^ Multiply(IMatrix<T>^ multiplier, IEnumerable<IVector<T>^>^ vectors) 
		{
			throw gcnew NotImplementedException();
		}
		
		virtual IEnumerable<IVector<T>^>^ Multiply(IEnumerable<IVector<T>^>^ vectors, IMatrix<T>^ multiplier) 
		{
			throw gcnew NotImplementedException();
		}

		virtual void Multiply(IEnumerable<array<T>^>^ vectorsComponents, IMatrix<T>^ multiplier) { }
        virtual void Multiply(IMatrix<T>^ multiplier, IEnumerable<array<T>^>^ vectorsComponents) { }

		virtual void Multiply(IMatrix<T>^ multiplier, array<T>^ vectorComponents) { }
		virtual void Multiply(array<T>^ vectorComponents, IMatrix<T>^ multiplier) { }

		virtual void Multiply(IMatrix<T>^ multiplier, array<array<T>^>^ matrixElements) { }
		virtual void Multiply(array<array<T>^>^ matrixElements, IMatrix<T>^ multiplier) { }

        virtual IMatrix<T>^ ScalarMultiply(IMatrix<T>^ lhs, T rhs) 
		{
			throw gcnew NotImplementedException();
		}
		
        virtual void ScalarMultiply(array<array<T>^>^ lhs, T rhs) 
		{
			throw gcnew NotImplementedException();
		}

        virtual IMatrix<T>^ Invert(IMatrix<T>^ matrix) 
		{
			throw gcnew NotImplementedException();
		}
		
        virtual IMatrix<T>^ Negate(IMatrix<T>^ matrix) 
		{
			throw gcnew NotImplementedException();
		}
		
        virtual void Negate(array<array<T>^>^ matrix) 
		{
			throw gcnew NotImplementedException();
		}

		virtual void Rotate(IMatrix<T>^ matrix, IVector<T>^ axis, Double radians) 
		{ 
			throw gcnew NotImplementedException();
		}
		
		virtual void Scale(IMatrix<T>^ matrix, IVector<T>^ amount) 
		{ 
			throw gcnew NotImplementedException();
		}
		
		virtual void Shear(IMatrix<T>^ matrix, IVector<T>^ shearVector) 
		{
			throw gcnew NotImplementedException(); 
		}
		
		virtual void Translate(IAffineTransformMatrix<T>^ affineMatrix, IVector<T>^ amount) 
		{
			throw gcnew NotImplementedException(); 
		}

		virtual Double FrobeniusNorm(IMatrix<T>^ matrix) 
		{
			throw gcnew NotImplementedException();
		}
		
		virtual Double OneNorm(IMatrix<T>^ matrix) 
		{
			throw gcnew NotImplementedException();
		}
		
		virtual Double TwoNorm(IMatrix<T>^ matrix) 
		{
			throw gcnew NotImplementedException();
		}
		
		virtual Double InfinityNorm(IMatrix<T>^ matrix) 
		{
			throw gcnew NotImplementedException();
		}
		
		virtual Double Determinant(IMatrix<T>^ matrix) 
		{
			throw gcnew NotImplementedException();
		}
		
		virtual Int32 Rank(IMatrix<T>^ matrix) 
		{
			throw gcnew NotImplementedException();
		}
		
		virtual Double Condition(IMatrix<T>^ matrix) 
		{
			throw gcnew NotImplementedException();
		}
		
		virtual Double Trace(IMatrix<T>^ matrix) 
		{
			throw gcnew NotImplementedException();
		}
		
		virtual IMatrix<T>^ Solve(IMatrix<T>^ a, IMatrix<T>^ b) 
		{
			throw gcnew NotImplementedException();
		}
		
		virtual IMatrix<T>^ SolveTranspose(IMatrix<T>^ a, IMatrix<T>^ b) 
		{
			throw gcnew NotImplementedException();
		}
		
		virtual IMatrix<T>^ Transpose(IMatrix<T>^ matrix) 
		{
			throw gcnew NotImplementedException();
		}

		virtual void SetMatrix(IMatrix<T>^ source, IMatrix<T>^ destination)
		{
			throw gcnew NotImplementedException();
		}
		
		virtual ILuDecomposition<T>^ GetLuDecomposition(IMatrix<T>^ matrix) 
		{
			throw gcnew NotImplementedException();
		}
		
		virtual IQrDecomposition<T>^ GetQrDecomposition(IMatrix<T>^ matrix) 
		{
			throw gcnew NotImplementedException();
		}
		
		virtual ICholeskyDecomposition<T>^ GetCholeskyDecomposition(IMatrix<T>^ matrix) 
		{
			throw gcnew NotImplementedException();
		}
		
		virtual ISingularValueDecomposition<T>^ GetSingularValueDecomposition(IMatrix<T>^ matrix) 
		{
			throw gcnew NotImplementedException();
		}
		
		virtual IEigenvalueDecomposition<T>^ GetEigenvalueDecomposition(IMatrix<T>^ matrix) 
		{
			throw gcnew NotImplementedException();
		}

		virtual IVector<T>^ Add(IVector<T>^ addend, IVector<T>^ adder)
		{
			throw gcnew NotImplementedException();
		}
		
		virtual IVector<T>^ Subtract(IVector<T>^ addend, IVector<T>^ adder)
		{
			throw gcnew NotImplementedException();
		}
	};
} } }
